use crate::app::event::Event;
use crate::app::state::{Consumed, SessionHelper};
use crate::app::DynError;
use crate::sketchbook::data_structs::{RegulationData, StatPropertyData};
use crate::sketchbook::event_utils::{
make_reversible, mk_model_event, mk_model_state_change, mk_stat_prop_event,
};
use crate::sketchbook::ids::VarId;
use crate::sketchbook::model::{Essentiality, ModelState, Monotonicity};
use crate::sketchbook::properties::shortcuts::*;
use crate::sketchbook::properties::StatProperty;
use crate::sketchbook::JsonSerde;
const ADD_REGULATION_PATH: &str = "add";
const ADD_RAW_REGULATION_PATH: &str = "add_raw";
const REMOVE_REGULATION_PATH: &str = "remove";
const REMOVE_RAW_REGULATION_PATH: &str = "remove_raw";
const SET_SIGN_PATH: &str = "set_sign";
const SET_SIGN_RAW_PATH: &str = "set_sign_raw";
const SET_ESSENTIALITY_PATH: &str = "set_essentiality";
const SET_ESSENTIALITY_RAW_PATH: &str = "set_essentiality_raw";
impl ModelState {
pub(super) fn perform_regulation_event(
&mut self,
event: &Event,
at_path: &[&str],
) -> Result<Consumed, DynError> {
let component_name = "model/regulation";
if Self::starts_with(ADD_REGULATION_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
self.event_add_regulation(event)
} else if Self::starts_with(ADD_RAW_REGULATION_PATH, at_path).is_some() {
Self::assert_path_length(at_path, 1, component_name)?;
self.event_add_regulation_raw(event)
} else {
Self::assert_path_length(at_path, 3, component_name)?;
let regulator_id_str = at_path.first().unwrap();
let target_id_str = at_path.get(1).unwrap();
let regulator_id = self.get_var_id(regulator_id_str)?;
let target_id = self.get_var_id(target_id_str)?;
self.event_modify_regulation(event, &at_path[2..], regulator_id, target_id)
}
}
pub(super) fn event_add_regulation(&mut self, event: &Event) -> Result<Consumed, DynError> {
let component_name = "model/regulation";
let payload = Self::clone_payload_str(event, component_name)?;
let reg_data = RegulationData::from_json_str(payload.as_str())?;
let mut event_list = Vec::new();
let input_var = VarId::new(®_data.regulator)?;
let target_var = VarId::new(®_data.target)?;
if reg_data.essential != Essentiality::Unknown {
let prop_id = StatProperty::get_essentiality_prop_id(&input_var, &target_var);
let prop = mk_essentiality_prop(&input_var, &target_var, reg_data.essential);
let prop_payload = StatPropertyData::from_property(&prop_id, &prop).to_json_str();
let prop_event = mk_stat_prop_event(&["add"], Some(&prop_payload));
event_list.push(prop_event);
}
if reg_data.sign != Monotonicity::Unknown {
let prop_id = StatProperty::get_monotonicity_prop_id(&input_var, &target_var);
let prop = mk_monotonicity_prop(&input_var, &target_var, reg_data.sign);
let prop_payload = StatPropertyData::from_property(&prop_id, &prop).to_json_str();
let prop_event = mk_stat_prop_event(&["add"], Some(&prop_payload));
event_list.push(prop_event);
}
let reg_event = mk_model_event(&["regulation", "add_raw"], Some(&payload));
event_list.push(reg_event);
Ok(Consumed::Restart(event_list))
}
pub(super) fn event_add_regulation_raw(&mut self, event: &Event) -> Result<Consumed, DynError> {
let component_name = "model/regulation";
let payload = Self::clone_payload_str(event, component_name)?;
let reg_data = RegulationData::from_json_str(payload.as_str())?;
let regulator_id = self.get_var_id(®_data.regulator)?;
let target_id = self.get_var_id(®_data.target)?;
let sign: Monotonicity = reg_data.sign;
let essential: Essentiality = reg_data.essential;
self.add_regulation(regulator_id, target_id, essential, sign)?;
let state_change = mk_model_state_change(&["regulation", "add"], ®_data);
let reverse_at_path = [
"regulation",
®_data.regulator,
®_data.target,
"remove_raw",
];
let reverse_event = mk_model_event(&reverse_at_path, None);
Ok(make_reversible(state_change, event, reverse_event))
}
pub(super) fn event_modify_regulation(
&mut self,
event: &Event,
at_path: &[&str],
regulator_id: VarId,
target_id: VarId,
) -> Result<Consumed, DynError> {
let component_name = "model/regulation";
if Self::starts_with(REMOVE_REGULATION_PATH, at_path).is_some() {
let mut event_list = Vec::new();
let reg_event_path = [
"regulation",
regulator_id.as_str(),
target_id.as_str(),
"remove_raw",
];
let reg_event = mk_model_event(®_event_path, None);
event_list.push(reg_event);
let original_reg = self.get_regulation(®ulator_id, &target_id)?.clone();
if *original_reg.get_essentiality() != Essentiality::Unknown {
let prop_id = StatProperty::get_essentiality_prop_id(®ulator_id, &target_id);
let prop_event = mk_stat_prop_event(&[prop_id.as_str(), "remove"], None);
event_list.push(prop_event);
}
if *original_reg.get_sign() != Monotonicity::Unknown {
let prop_id = StatProperty::get_monotonicity_prop_id(®ulator_id, &target_id);
let prop_event = mk_stat_prop_event(&[prop_id.as_str(), "remove"], None);
event_list.push(prop_event);
}
Ok(Consumed::Restart(event_list))
} else if Self::starts_with(REMOVE_RAW_REGULATION_PATH, at_path).is_some() {
Self::assert_payload_empty(event, component_name)?;
let original_reg = self.get_regulation(®ulator_id, &target_id)?.clone();
let reg_data = RegulationData::from_reg(&original_reg);
self.remove_regulation(®ulator_id, &target_id)?;
let state_change = mk_model_state_change(&["regulation", "remove"], ®_data);
let reverse_at_path = ["regulation", "add_raw"];
let payload = reg_data.to_json_str();
let reverse_event = mk_model_event(&reverse_at_path, Some(&payload));
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_SIGN_PATH, at_path).is_some() {
let sign_str = Self::clone_payload_str(event, component_name)?;
let new_sign = Monotonicity::from_json_str(&sign_str)?;
let original_reg = self.get_regulation(®ulator_id, &target_id)?;
let orig_sign = *original_reg.get_sign();
if orig_sign == new_sign {
return Ok(Consumed::NoChange);
}
let mut event_list = Vec::new();
let reg_event_path = [
"regulation",
regulator_id.as_str(),
target_id.as_str(),
"set_sign_raw",
];
let reg_event = mk_model_event(®_event_path, Some(&sign_str));
event_list.push(reg_event);
let prop_id = StatProperty::get_monotonicity_prop_id(®ulator_id, &target_id);
if orig_sign == Monotonicity::Unknown {
let prop = mk_monotonicity_prop(®ulator_id, &target_id, new_sign);
let prop_payload = StatPropertyData::from_property(&prop_id, &prop).to_json_str();
let prop_event = mk_stat_prop_event(&["add"], Some(&prop_payload));
event_list.push(prop_event);
} else if new_sign == Monotonicity::Unknown {
let prop_event = mk_stat_prop_event(&[prop_id.as_str(), "remove"], None);
event_list.push(prop_event);
} else {
let prop = mk_monotonicity_prop(®ulator_id, &target_id, new_sign);
let prop_payload = StatPropertyData::from_property(&prop_id, &prop).to_json_str();
let prop_event =
mk_stat_prop_event(&[prop_id.as_str(), "set_content"], Some(&prop_payload));
event_list.push(prop_event);
}
Ok(Consumed::Restart(event_list))
} else if Self::starts_with(SET_SIGN_RAW_PATH, at_path).is_some() {
let sign_str = Self::clone_payload_str(event, component_name)?;
let new_sign = Monotonicity::from_json_str(&sign_str)?;
let original_reg = self.get_regulation(®ulator_id, &target_id)?;
let orig_sign = *original_reg.get_sign();
if orig_sign == new_sign {
return Ok(Consumed::NoChange);
}
self.change_regulation_sign(®ulator_id, &target_id, &new_sign)?;
let new_reg = self.get_regulation(®ulator_id, &target_id)?;
let reg_data = RegulationData::from_reg(new_reg);
let state_change = mk_model_state_change(&["regulation", "set_sign"], ®_data);
let mut reverse_event = event.clone();
reverse_event.payload = Some(orig_sign.to_json_str());
Ok(make_reversible(state_change, event, reverse_event))
} else if Self::starts_with(SET_ESSENTIALITY_PATH, at_path).is_some() {
let essentiality_str = Self::clone_payload_str(event, component_name)?;
let new_essentiality = Essentiality::from_json_str(&essentiality_str)?;
let original_reg = self.get_regulation(®ulator_id, &target_id)?;
let orig_essentiality = *original_reg.get_essentiality();
if orig_essentiality == new_essentiality {
return Ok(Consumed::NoChange);
}
let mut event_list = Vec::new();
let reg_event_path = [
"regulation",
regulator_id.as_str(),
target_id.as_str(),
"set_essentiality_raw",
];
let reg_event = mk_model_event(®_event_path, Some(&essentiality_str));
event_list.push(reg_event);
let prop_id = StatProperty::get_essentiality_prop_id(®ulator_id, &target_id);
if orig_essentiality == Essentiality::Unknown {
let prop = mk_essentiality_prop(®ulator_id, &target_id, new_essentiality);
let prop_payload = StatPropertyData::from_property(&prop_id, &prop).to_json_str();
let prop_event = mk_stat_prop_event(&["add"], Some(&prop_payload));
event_list.push(prop_event);
} else if new_essentiality == Essentiality::Unknown {
let prop_event = mk_stat_prop_event(&[prop_id.as_str(), "remove"], None);
event_list.push(prop_event);
} else {
let prop = mk_essentiality_prop(®ulator_id, &target_id, new_essentiality);
let prop_payload = StatPropertyData::from_property(&prop_id, &prop).to_json_str();
let prop_event =
mk_stat_prop_event(&[prop_id.as_str(), "set_content"], Some(&prop_payload));
event_list.push(prop_event);
}
Ok(Consumed::Restart(event_list))
} else if Self::starts_with(SET_ESSENTIALITY_RAW_PATH, at_path).is_some() {
let essentiality_str = Self::clone_payload_str(event, component_name)?;
let new_essentiality = Essentiality::from_json_str(&essentiality_str)?;
let original_reg = self.get_regulation(®ulator_id, &target_id)?;
let orig_essentiality = *original_reg.get_essentiality();
if orig_essentiality == new_essentiality {
return Ok(Consumed::NoChange);
}
self.change_regulation_essentiality(®ulator_id, &target_id, &new_essentiality)?;
let new_reg = self.get_regulation(®ulator_id, &target_id)?;
let reg_data = RegulationData::from_reg(new_reg);
let state_change =
mk_model_state_change(&["regulation", "set_essentiality"], ®_data);
let mut reverse_event = event.clone();
reverse_event.payload = Some(orig_essentiality.to_json_str());
Ok(make_reversible(state_change, event, reverse_event))
} else {
Self::invalid_path_error_specific(at_path, component_name)
}
}
}